﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Genuilder.Extensibility
{
	public abstract class CodeRepositoryBase : ICodeRepository
	{
		List<CodeItem> _AddedWhenNotInitializing = new List<CodeItem>();
		bool _IsInitializing;
		public void Initialize()
		{
			try
			{
				_IsInitializing = true;
				var codeItemHistories = GetCodeItemHistories();
				List<CodeItem> trackedCodeItems = new List<CodeItem>();
				CodeItemCreatedHandler onCodeItemTracked = (i) => trackedCodeItems.Add(i);
				try
				{
					CodeItemCreated += onCodeItemTracked;
					foreach(var item in codeItemHistories.Select(h => h.CodeItem).Union(_AddedWhenNotInitializing))
					{
						OnCodeItemCreated(item);
					}
					foreach(var history in codeItemHistories)
					{
						history.PlayChange();
					}
				}
				finally
				{
					CodeItemCreated -= onCodeItemTracked;
				}
				OnInitialized(trackedCodeItems);
			}
			finally
			{
				_AddedWhenNotInitializing.Clear();
				_IsInitializing = false;
			}
		}

		protected virtual void OnInitialized(IEnumerable<CodeItem> trackedItems)
		{

		}

		private void OnCodeItemCreated(CodeItem item)
		{
			item._IsCreating = true;
			try
			{
				if(CodeItemCreated != null)
					CodeItemCreated(item);
			}
			finally
			{
				item._IsCreating = false;
			}
		}


		#region ICodeRepository Members

		public CodeItem Add(string name)
		{
			CodeItem item = CreateCodeItem(name, CodeItemState.Exist);
			if(_IsInitializing)
				OnCodeItemCreated(item);
			else
				_AddedWhenNotInitializing.Add(item);
			return item;
		}

		protected abstract CodeItem CreateCodeItem(string name, CodeItemState state);
		protected abstract IEnumerable<CodeItemHistory> GetCodeItemHistories();

		public event CodeItemCreatedHandler CodeItemCreated;


		#endregion
	}


	public class CodeItemHistory
	{
		public CodeItemHistory(CodeItem item)
		{
			_CodeItem = item;
		}
		private readonly CodeItem _CodeItem;
		public CodeItem CodeItem
		{
			get
			{
				return _CodeItem;
			}
		}

		public bool Modified
		{
			get;
			set;
		}

		public CodeItemState NewState
		{
			get;
			set;
		}

		public virtual void PlayChange()
		{
			if(_CodeItem.State != NewState)
				_CodeItem.ChangeState(NewState);
			if(Modified)
				_CodeItem.OnContentChanged();
		}
	}
}
